package com.hua.utility.encrypt;

import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class EncryptionAlgorithm {

	/**
	 * (非可逆加密) ALGORITHM 算法 <br>
	 * 可替换为以下任意一种算法，同时key值的size相应改变。
	 * 
	 * <pre>
	 * DES          		key size must be equal to 56
	 * DESede(TripleDES) 	key size must be equal to 112 or 168
	 * AES          		key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available
	 * Blowfish     		key size must be multiple of 8, and can only range from 32 to 448 (inclusive)
	 * RC2          		key size must be between 40 and 1024 bits
	 * RC4(ARCFOUR) 		key size must be between 40 and 1024 bits
	 * </pre>
	 * 
	 * 在Key toKey(byte[] key)方法中使用下述代码
	 * <code>SecretKey secretKey = new SecretKeySpec(key, encryptType);</code>
	 * 替换 <code>
	 * DESKeySpec dks = new DESKeySpec(key);
	 * SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(encryptType);
	 * SecretKey secretKey = keyFactory.generateSecret(dks);
	 * </code>
	 */
	public static final String KEY_DES = "DES";
	public static final String KEY_DESEDE = "DESede";
	public static final String KEY_AES = "AES";
	public static final String KEY_BLOWFISH = "Blowfish";
	public static final String KEY_RC2 = "RC2";
	public static final String KEY_RC4 = "RC4";

	private String encryptType = "DES";

	/**
	 * 转换密钥<br>
	 * 
	 * @param key
	 * @return
	 * @throws InvalidKeySpecException
	 * @throws NoSuchAlgorithmException
	 * @throws InvalidKeyException
	 * @throws Exception
	 */
	private Key toKey(byte[] key) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException {
		SecretKey secretKey = null;
		if (KEY_DES.equalsIgnoreCase(encryptType)) {
			secretKey = getDESKey(key);
		} else if (KEY_DESEDE.equalsIgnoreCase(encryptType) || "TripleDES".equalsIgnoreCase(encryptType)) {
			secretKey = getDESKey(key);
		} else if (KEY_AES.equalsIgnoreCase(encryptType)) {
			secretKey = getOtherKey(key);
		} else if (KEY_BLOWFISH.equalsIgnoreCase(encryptType)) {
			secretKey = getOtherKey(key);
		} else if (KEY_RC2.equalsIgnoreCase(encryptType)) {
			secretKey = getOtherKey(key);
		} else if (KEY_RC4.equalsIgnoreCase(encryptType) || "ARCFOUR".equalsIgnoreCase(encryptType)) {
			secretKey = getOtherKey(key);
		} else {
			secretKey = getDESKey(key);
		}
		return secretKey;
	}

	private SecretKey getDESKey(byte[] key)
			throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException {
		DESKeySpec dks = new DESKeySpec(key);
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(encryptType);
		SecretKey secretKey = keyFactory.generateSecret(dks);
		return secretKey;
	}

	private SecretKey getOtherKey(byte[] key) {
		SecretKey secretKey = new SecretKeySpec(key, encryptType);
		return secretKey;
	}

	/**
	 * 解密
	 * 
	 * @param data
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public byte[] decrypt(byte[] data, String key) throws Exception {
		Key k = toKey((new BASE64Decoder()).decodeBuffer(key));

		Cipher cipher = Cipher.getInstance(encryptType);
		cipher.init(Cipher.DECRYPT_MODE, k);

		return cipher.doFinal(data);
	}

	/**
	 * 加密
	 * 
	 * @param data
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public byte[] encrypt(byte[] data, String key) throws Exception {
		Key k = toKey((new BASE64Decoder()).decodeBuffer(key));
		Cipher cipher = Cipher.getInstance(encryptType);
		cipher.init(Cipher.ENCRYPT_MODE, k);

		return cipher.doFinal(data);
	}

	/**
	 * 生成密钥
	 * 
	 * @return
	 * @throws Exception
	 */
	public String initKey() throws Exception {
		return initKey(null);
	}

	/**
	 * 生成密钥
	 * 
	 * @param seed
	 * @return
	 * @throws Exception
	 */
	public String initKey(String seed) throws Exception {
		SecureRandom secureRandom = null;

		if (seed != null) {
			secureRandom = new SecureRandom((new BASE64Decoder()).decodeBuffer(seed));
		} else {
			secureRandom = new SecureRandom();
		}

		KeyGenerator kg = KeyGenerator.getInstance(encryptType);
		kg.init(secureRandom);

		SecretKey secretKey = kg.generateKey();

		return (new BASE64Encoder()).encodeBuffer(secretKey.getEncoded());
	}

	public String getEncryptType() {
		return encryptType;
	}

	public void setEncryptType(String encryptType) {
		if (KEY_DES.equalsIgnoreCase(encryptType)) {
			this.encryptType = KEY_DES;
		} else if (KEY_DESEDE.equalsIgnoreCase(encryptType) || "TripleDES".equalsIgnoreCase(encryptType)) {
			this.encryptType = KEY_DESEDE;
		} else if (KEY_AES.equalsIgnoreCase(encryptType)) {
			this.encryptType = KEY_AES;
		} else if (KEY_BLOWFISH.equalsIgnoreCase(encryptType)) {
			this.encryptType = KEY_BLOWFISH;
		} else if (KEY_RC2.equalsIgnoreCase(encryptType)) {
			this.encryptType = KEY_RC2;
		} else if (KEY_RC4.equalsIgnoreCase(encryptType) || "ARCFOUR".equalsIgnoreCase(encryptType)) {
			this.encryptType = KEY_RC4;
		} else {
			this.encryptType = KEY_DES;
		}
	}

}